package org.road0329.tools.proto_parse_tool.ems;

import org.road0329.tools.proto_parse_tool.utils.DateUtil;
import org.road0329.tools.proto_parse_tool.utils.ProtocolUtils;
import org.road0329.tools.proto_parse_tool.utils.StringUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import java.math.BigDecimal;
import java.util.*;

/**
 * Created by Administrator on 2018-09-26.
 */
@Component
public class Protocol188Util {
    private static Logger logger = LoggerFactory.getLogger(Protocol188Util.class);

    private static final short EVENT_ITEM_BATTERY_UNDERVOLTAGE = 201;//电池欠压
    private static final String TYPE_NUM_WATER = "10";//水表

    private static final short STATUS_OPEN = 0;//阀门 打开
    private static final short STATUS_CLOSE = 1;//阀门 关闭

    private static final short EXPECT_CMD_CHANGE_STATION_ADDR = 1; //主站地址设置

    public static PointCommInfo parseCommand(byte[] buf) throws Exception {
        //使用报文中水表地址查询计量点信息
        int index = 2;
        String pointCommAddr = String.format("%02X%02X%02X%02X%02X%02X%02X", buf[index + 6], buf[index + 5], buf[index + 4], buf[index + 3],
                buf[index + 2], buf[index + 1], buf[index]);//地址

        PointCommInfo pointComm = new PointCommInfo();
        pointComm.setCommAddr(pointCommAddr);

        int len = ProtocolUtils.Unsignd(buf[9]);
        if (len > 0) {
            int C = ProtocolUtils.Unsignd(buf[9]);
            switch (C) {
                case 0x81://召读数据返回
                    pointComm = parseCallData(buf, pointComm);
                    break;
                case 0x84://拉合闸返回
                    pointComm = parseSwitchReCall(buf, pointComm);
                    break;
                default:
                    throw new Exception("188-2004表暂不支持该操作:" + C);
            }
        } else if (len == 0) {//确认帧
            pointComm.setResultData("确认帧");
        }
        return pointComm;
    }

    private static PointCommInfo parseSwitchReCall(byte[] newBytes, PointCommInfo pointComm) {
        if (ProtocolUtils.Unsignd(newBytes[14]) == 0) {//合闸成功
            pointComm.setResultData("合闸成功");
        } else if (ProtocolUtils.Unsignd(newBytes[14]) == 0) {//拉闸成功
            pointComm.setResultData("拉闸成功");
        }
        return pointComm;
    }

    private static BigDecimal getDecimalValue(String value, String scale) {
        if (StringUtil.isEmpty(value) || !StringUtil.isDigits(value)) {
            return null;
        }
        BigDecimal decimalValue = new BigDecimal(value);
        if ("29".equals(scale)) {
            decimalValue = decimalValue.divide(BigDecimal.valueOf(100000), 5, BigDecimal.ROUND_HALF_UP);
        } else if ("2A".equalsIgnoreCase(scale)) {
            decimalValue = decimalValue.divide(BigDecimal.valueOf(10000), 4, BigDecimal.ROUND_HALF_UP);
        } else if ("2B".equalsIgnoreCase(scale)) {
            decimalValue = decimalValue.divide(BigDecimal.valueOf(1000), 3, BigDecimal.ROUND_HALF_UP);
        } else if ("2C".equalsIgnoreCase(scale)) {
            decimalValue = decimalValue.divide(BigDecimal.valueOf(100), 2, BigDecimal.ROUND_HALF_UP);
        } else if ("2D".equalsIgnoreCase(scale)) {
            decimalValue = decimalValue.divide(BigDecimal.valueOf(10), 1, BigDecimal.ROUND_HALF_UP);
        }
        return decimalValue;
    }

    private static  PointCommInfo parseCallData(byte[] newBytes, PointCommInfo pointComm) {
        Map<String, Object> resultValue = new LinkedHashMap<>();
        int index = 0;
        String di = String.format("%02X%02X", newBytes[12], newBytes[11]);
        String value, scale;
        byte[] decimal ;
        BigDecimal decimalValue, decimalValue2;
        BigDecimal freezeDecimalValue;
        if ("901F".equalsIgnoreCase(di) || "1F90".equalsIgnoreCase(di)) {
            index = 14;

            value = ProtocolUtils.getByteToHexStringDesc(newBytes, index, 4, "");
            scale = ProtocolUtils.getByteToHexStringDesc(newBytes, index + 4, 1, "");
            decimalValue = getDecimalValue(value, scale);
            index += 5;// 当前累计用量

            value = ProtocolUtils.getByteToHexStringDesc(newBytes, index, 4, "");
            scale = ProtocolUtils.getByteToHexStringDesc(newBytes, index + 4, 1, "");
            freezeDecimalValue = getDecimalValue(value, scale);
            index += 5;// 结算日累计流量

            String dateTime = ProtocolUtils.getByteToHexStringDesc(newBytes, index, 7, "");
            Date dataTime = null;
            if (dateTime.indexOf("0000") == 0
                    || dateTime.indexOf("EEEE") == 0 || dateTime.indexOf("eeee") == 0
                    || dateTime.indexOf("FFFF") == 0 || dateTime.indexOf("ffff") == 0) {
                dataTime = new Date(0);
            } else {
                dataTime = DateUtil.StrToDate(dateTime, DateUtil.TIME_LONG_14);
            }

            index += 7;//7字节时间
            short valveStatus = ProtocolWaterUtil.getStatus(newBytes[index]);
            short batterStatus = 0;
            if (!"FF".equalsIgnoreCase(String.format("%02X", newBytes[index]))) {
                if ((newBytes[index] & 0x04) != 0x00) {//电池电压欠压
                    batterStatus = 1;
                }
            }
            resultValue.put("dataTime", DateUtil.DateToLongStr(dataTime));
            resultValue.put("currentCumulant", decimalValue);
            resultValue.put("monthFreezeCumulant", freezeDecimalValue);
            resultValue.put("valveStatus", valveStatus);
            resultValue.put("batterStatus", batterStatus);
            pointComm.setResultValue(resultValue);

        } else if ("831C".equalsIgnoreCase(di)) {
            index = 13;
            StringBuilder builder = new StringBuilder();
            builder.append(String.format("%d", (newBytes[index++]) & 0xFF)).append(".");
            builder.append(String.format("%d", (newBytes[index++] & 0xFF))).append(".");
            builder.append(String.format("%d", (newBytes[index++] & 0xFF))).append(".");
            builder.append(String.format("%d", (newBytes[index++] & 0xFF))).append(",");
            builder.append(newBytes[index++] + newBytes[index++] * 256).append(",");
            builder.append(String.format("%02X", (newBytes[index++] & 0xFF)));
            pointComm.setResultData(builder.toString());
        }else if ("8504".equalsIgnoreCase(di) || "0485".equalsIgnoreCase(di) || "C10B".equalsIgnoreCase(di) || "0BC1".equalsIgnoreCase(di)) {
            if(newBytes[14] != 00) {
                logger.info("非日冻结数据, 不解析");
                return pointComm;
            }
            index +=16;
            String dateTime = ProtocolUtils.getByteToHexStringDesc(newBytes, index, 6, "");
            Date dataTime = null;
            if (dateTime.indexOf("0000") == 0
                    || dateTime.indexOf("EEEE") == 0 || dateTime.indexOf("eeee") == 0
                    || dateTime.indexOf("FFFF") == 0 || dateTime.indexOf("ffff") == 0) {
                dataTime = new Date(0);
            } else {
                dataTime = DateUtil.StrToDate(dateTime, DateUtil.TIME_LONG_12);
            }
            index += 8;
            decimal = new byte[4];
            System.arraycopy(newBytes, index, decimal, 0, 4);
            decimalValue = ProtocolUtils.byteToBigDecimal(decimal, 0, 4, 4);
            index +=4;
            decimal = new byte[4];
            System.arraycopy(newBytes, index, decimal, 0, 4);
            decimalValue2 = ProtocolUtils.byteToBigDecimal(decimal, 0, 4, 4);
            if(decimalValue != null && decimalValue2 != null ) {
                freezeDecimalValue = decimalValue.subtract(decimalValue2);
                if(freezeDecimalValue.compareTo(BigDecimal.ZERO) < 0) {
                    logger.info("日冻结数据:{} = 正向累积流量:{} -反向累积流量:{} < 0", freezeDecimalValue, decimalValue, decimalValue2);
                    return pointComm;
                }

                resultValue.put("日冻结时间:" , DateUtil.DateToLongStr(dataTime));
                resultValue.put("日冻结数据:" , freezeDecimalValue);
                resultValue.put("正向累积流量:" , decimalValue);
                resultValue.put("反向累积流量:" , decimalValue2);
                pointComm.setResultValue(resultValue);
            }
        }
        return pointComm;
    }
}
